Android自定义控件实战

您所在的位置:网站首页 android studio上下滑动控件 Android自定义控件实战

Android自定义控件实战

2024-06-07 11:56| 来源: 网络整理| 查看: 265

最近做项目,遇到一个需要实现滚动选择的需求。以前做过一个自定义实现滚动选择的view(https://blog.csdn.net/u014763302/article/details/53104814),但发现不大符合需求。本着快速实现的目标,就找到了这为大神的博客(https://blog.csdn.net/zhongkejingwang/article/details/38513301),看了下实现的差不多了,就拿过来用,顺便加了一些小功能,并对存在的bug做了一些优化,特记录。

目前需求: 上下可循环滚动选择点击按钮自动上下滚动一格 效果如下:

在这里插入图片描述

思路讲解:

由于代码本身是基于上面博文的基础上来的,逻辑大部分还是没变,需要细节的请移步开头的链接,博文中思路细节大神讲的很明白。 说下我添加的功能及优化的地方:

点击按钮自动滚动一格:原来的滚动实现是基于触摸事件+记录滑动距离,因此自动滚动也基于一样的逻辑:主动调用触摸方法模拟触摸事件。原博文存在瞬滑时回滚很多造成不友好现象,修复是在ACTION_UP时通过计算矫正滑动位置和data item的对应关系。

下面上代码。

package com.example.wheelview; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.FontMetricsInt; import android.graphics.Paint.Style; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * 滚动选择器,https://blog.csdn.net/zhongkejingwang/article/details/38513301 * * @author huanghp */ public class PickerView extends View { public static final String TAG = "PickerView"; //minTextSize和text之间间距之比 public static final float MARGIN_ALPHA = 1.56f; //自动回滚到中间的速度 public static final byte SPEED = 2; public static final byte PERIOD = 10; public static final byte CODE = 0X10; private List mDataList; /** * 选中的位置,这个位置是mDataList的中心位置,一直不变 */ private int mCurrentSelected; private Paint mPaint; private float mMaxTextSize = 48; private float mMinTextSize = 32; private float mMaxTextAlpha = 255; private float mMinTextAlpha = 120; private int mColorText = 0xffffff; private int mViewHeight; private int mViewWidth; private float mLastDownY; //滑动的距离 private float mMoveLen = 0; private boolean isInit = false; private onSelectListener mSelectListener; private volatile boolean isInAnimate; private Handler updateHandler = new Handler() { @Override public void handleMessage(Message msg) { if (Math.abs(mMoveLen) // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚 mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED; sendEmptyMessageDelayed(CODE, PERIOD); } invalidate(); } }; public PickerView(Context context) { this(context, null); } public PickerView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public void setOnSelectListener(onSelectListener listener) { mSelectListener = listener; } private void performSelect() { if (mSelectListener != null) mSelectListener.onSelect(mDataList.get(mCurrentSelected)); } public void setData(List datas) { if (datas != null) { mDataList.addAll(datas); } mCurrentSelected = mDataList.size() / 2; performSelect(); invalidate(); } private void moveHeadToTail() { String head = mDataList.get(0); mDataList.remove(0); mDataList.add(head); } private void moveTailToHead() { String tail = mDataList.get(mDataList.size() - 1); mDataList.remove(mDataList.size() - 1); mDataList.add(0, tail); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mViewHeight = getMeasuredHeight(); mViewWidth = getMeasuredWidth(); // 按照View的高度计算字体大小 // mMaxTextSize = mViewHeight / 4.0f; // mMinTextSize = mMaxTextSize / 2f; isInit = true; invalidate(); } private void init() { mDataList = new ArrayList(); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Style.FILL); mPaint.setTextAlign(Align.CENTER); mPaint.setColor(mColorText); // mPaint.setTypeface(Typeface.create("eurostile", Typeface.NORMAL)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (isInit) drawData(canvas); } private void drawData(Canvas canvas) { if (mDataList.isEmpty()) return; // 先绘制选中的text再往上往下绘制其余的text float scale = parabola(mViewHeight / 4.0f, mMoveLen); float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize; mPaint.setTextSize(size); mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha)); // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标 float x = (float) (mViewWidth / 2.0); float y = (float) (mViewHeight / 2.0 + mMoveLen); FontMetricsInt fmi = mPaint.getFontMetricsInt(); float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));//这里是经过简化后的公式 canvas.drawText(mDataList.get(mCurrentSelected), x, baseline, mPaint); // 绘制上方data for (int i = 1; (mCurrentSelected - i) >= 0; i++) { drawOtherText(canvas, i, -1); } // 绘制下方data for (int i = 1; (mCurrentSelected + i) float d = (float) (MARGIN_ALPHA * mMinTextSize * position + type * mMoveLen); float scale = parabola(mViewHeight / 4.0f, d); float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize; mPaint.setTextSize(size); mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha)); float y = (float) (mViewHeight / 2.0 + type * d); FontMetricsInt fmi = mPaint.getFontMetricsInt(); float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0)); canvas.drawText(mDataList.get(mCurrentSelected + type * position), (float) (mViewWidth / 2.0), baseline, mPaint); } /** * 抛物线 * * @param zero 零点坐标 * @param x 偏移量 * @return scale */ private float parabola(float zero, float x) { float f = (float) (1 - Math.pow(x / zero, 2)); return f case MotionEvent.ACTION_DOWN: doDown(event); break; case MotionEvent.ACTION_MOVE: doMove(event); break; case MotionEvent.ACTION_UP: doUp(event); break; } return true; } private void doDown(MotionEvent event) { updateHandler.removeMessages(CODE); mLastDownY = event.getY(); } private void doMove(MotionEvent event) { mMoveLen += (event.getY() - mLastDownY); if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2) { // 往下滑超过离开距离 moveTailToHead(); mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize; } else if (mMoveLen // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置 if (Math.abs(mMoveLen) int m = (int) (Math.abs(mMoveLen) / (MARGIN_ALPHA * mMinTextSize / 2)); for (int i = 0; i if (isInAnimate) return; isInAnimate = true; final float[] values = up ? new float[]{MARGIN_ALPHA * mMinTextSize + 1, 0} : new float[]{0, MARGIN_ALPHA * mMinTextSize + 1}; ValueAnimator va = ValueAnimator.ofFloat(values); va.setDuration(100); va.setInterpolator(new LinearInterpolator()); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float v = (float) animation.getAnimatedValue(); doMove(MotionEvent.obtain(System.currentTimeMillis(), 0, 0, 0f, v, 0)); } }); va.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { doUp(null); isInAnimate = false; } @Override public void onAnimationStart(Animator animation) { doDown(MotionEvent.obtain(System.currentTimeMillis(), 0, 0, 0f, values[0], 0)); } }); va.start(); } public interface onSelectListener { void onSelect(String text); } }

谢谢!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3